import ZLMRTCClient from './ZLMRTCClient-v1.1.2.js';

/**
 * WRPlayer - A unified web video player SDK
 * Supports WebRTC, HLS, DASH and other formats with a common API
 */

class WRPlayer {
  /**
   * Create a new player instance
   * @param {Object} options - Player configuration
   * @param {HTMLVideoElement} options.element - Video element for playback
   * @param {string} options.url - URL for the stream/video
   * @param {string} [options.type] - Type of player ('webrtc', 'hls', 'dash', 'mp4'), if not provided will auto-detect from URL
   * @param {boolean} options.autoplay - Whether to start playing automatically
   * @param {boolean} options.debug - Enable debug logging
   * @param {Object} [options.dependencies] - External dependencies configuration
   * @param {string} [options.dependencies.hlsPath] - Path to hls.js if needs to be loaded dynamically
   * @param {string} [options.dependencies.dashPath] - Path to dash.js if needs to be loaded dynamically
   */
  constructor(options) {
    // Check if we're in a browser environment
    this.isBrowser = typeof window !== 'undefined';
    
    this.options = {
      autoplay: true,
      debug: false,
      dependencies: {
        hlsPath: 'https://cdn.jsdelivr.net/npm/hls.js@latest',
        dashPath: 'https://cdn.dashjs.org/latest/dash.all.min.js'
      },
      ...options
    };

    // Deep merge dependencies
    if (options.dependencies) {
      this.options.dependencies = {
        ...this.options.dependencies,
        ...options.dependencies
      };
    }

    // Skip initialization if not in browser (SSR)
    if (!this.isBrowser) {
      if (this.options.debug) {
        console.log('WRPlayer: Running in SSR mode, skipping initialization');
      }
      return;
    }

    this.element = this.options.element;
    if (!this.element) {
      throw new Error('WRPlayer: Video element is required');
    }

    this.player = null;
    this.eventHandlers = {};
    this.loadedDependencies = {};
    
    // WebRTC 状态管理，防止重复播放
    this.webrtcState = {
      isConnecting: false,
      isConnected: false,
      hasStartedReceiving: false,
      isRetryWithVideoOnly: false, // 回退策略标志
      retryCount: 0 // 重试计数
    };
    
    // 超时检测 ID
    this.webrtcTimeoutId = null;
    
    // Detect player type from URL if not specified
    if (!this.options.type && this.options.url) {
      this.options.type = this._detectTypeFromUrl(this.options.url);
      if (this.options.debug) {
        console.log(`WRPlayer: Auto-detected type: ${this.options.type} from URL: ${this.options.url}`);
      }
    }
    
    // Initialize the player based on the type
    this._initPlayer();
  }

  /**
   * Load external JavaScript dependency if needed
   * @private
   * @param {string} type - Type of dependency ('hls', 'dash')
   * @returns {Promise} - Promise that resolves when dependency is loaded
   */
  _loadDependency(type) {
    // Skip if not in browser
    if (!this.isBrowser) {
      return Promise.resolve();
    }

    // If already loaded, return resolved promise
    if (this.loadedDependencies[type]) {
      return Promise.resolve();
    }

    // Check if the dependency is already available globally
    if (type === 'hls' && typeof Hls !== 'undefined') {
      this.loadedDependencies[type] = true;
      return Promise.resolve();
    } else if (type === 'dash' && typeof dashjs !== 'undefined') {
      this.loadedDependencies[type] = true;
      return Promise.resolve();
    }

    // Need to dynamically load the script
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      let path;
      
      switch (type) {
        case 'hls':
          path = this.options.dependencies.hlsPath;
          break;
        case 'dash':
          path = this.options.dependencies.dashPath;
          break;
        default:
          reject(new Error(`WRPlayer: Unknown dependency type ${type}`));
          return;
      }
      
      if (this.options.debug) {
        console.log(`WRPlayer: Attempting to load ${type} from ${path}`);
      }
      
      script.src = path;
      script.async = true;
      
      script.onload = () => {
        if (this.options.debug) {
          console.log(`WRPlayer: Successfully loaded ${type} from ${path}`);
        }
        this.loadedDependencies[type] = true;
        resolve();
      };
      
      script.onerror = (error) => {
        console.error(`WRPlayer: Failed to load ${type} from ${path}`, error);
        reject(new Error(`WRPlayer: Failed to load ${type} from ${path}`));
      };
      
      document.head.appendChild(script);
    });
  }

  /**
   * Detect the stream type based on URL format
   * @private
   * @param {string} url - The URL to analyze
   * @returns {string} The detected type ('webrtc', 'hls', 'dash', 'mp4', etc.)
   */
  _detectTypeFromUrl(url) {
    // Skip if not in browser
    if (!this.isBrowser) {
      return 'unknown';
    }

    // Create URL object for easier parsing
    let urlObj;
    try {
      urlObj = new URL(url);
    } catch (e) {
      // If not a valid URL, try to extract extension from string
      const extension = url.split('.').pop().toLowerCase();
      return this._getTypeFromExtension(extension);
    }
    
    // Check for specific patterns in the URL
    
    // Check for WebRTC patterns
    if (
      urlObj.pathname.includes('webrtc') || 
      urlObj.searchParams.has('type') && urlObj.searchParams.get('type').includes('webrtc') ||
      urlObj.searchParams.has('protocol') && urlObj.searchParams.get('protocol').includes('webrtc') ||
      url.includes('sdp') ||
      url.includes('rtc')
    ) {
      return 'webrtc';
    }
    
    // Extract file extension from path
    const pathname = urlObj.pathname;
    const extension = pathname.split('.').pop().toLowerCase();
    
    return this._getTypeFromExtension(extension);
  }
  
  /**
   * Get media type from file extension
   * @private
   * @param {string} extension - The file extension
   * @returns {string} The media type
   */
  _getTypeFromExtension(extension) {
    switch (extension) {
      case 'm3u8':
      case 'm3u':
        return 'hls';
      case 'mpd':
        return 'dash';
      case 'mp4':
        return 'mp4';
      case 'webm':
        return 'webm';
      case 'ogg':
      case 'ogv':
        return 'ogg';
      default:
        // Default to HTML5 player for unknown types
        return 'mp4';
    }
  }

  /**
   * Initialize the appropriate player based on the type
   * @private
   */
  _initPlayer() {
    // Skip if not in browser
    if (!this.isBrowser) {
      return Promise.resolve();
    }

    const { type, url } = this.options;
    
    if (!url) {
      throw new Error('WRPlayer: URL is required');
    }
    
    if (!type) {
      throw new Error('WRPlayer: Could not determine player type');
    }

    // Use a Promise chain to handle dependency loading and player initialization
    let initPromise;

    switch (type.toLowerCase()) {
      case 'webrtc':
        // ZLMRTCClient is now imported directly, so it's always available.
        this._initWebRTCPlayer();
        initPromise = Promise.resolve();
        break;
      case 'hls':
        initPromise = this._loadDependency('hls')
          .then(() => this._initHLSPlayer())
          .catch(err => {
            console.error(err);
            throw new Error('WRPlayer: Failed to initialize HLS player. Make sure hls.js is available.');
          });
        break;
      case 'dash':
        initPromise = this._loadDependency('dash')
          .then(() => this._initDASHPlayer())
          .catch(err => {
            console.error(err);
            throw new Error('WRPlayer: Failed to initialize DASH player. Make sure dash.js is available.');
          });
        break;
      case 'mp4':
      case 'webm':
      case 'ogg':
      default:
        // HTML5 player doesn't need external dependencies
        this._initHTMLPlayer();
        initPromise = Promise.resolve();
        break;
    }

    // Start playback if autoplay is enabled, after initialization
    if (this.options.autoplay) {
      initPromise
        .then(() => {
          // Small timeout to ensure everything is ready
          setTimeout(() => this.play(), 100);
        })
        .catch(err => {
          this._dispatchEvent('error', { type: 'init_failed', details: err });
        });
    }

    return initPromise;
  }

  /**
   * Initialize a WebRTC player using ZLMRTCClient
   * @private
   */
  _initWebRTCPlayer() {
    if (!ZLMRTCClient) {
      throw new Error('WRPlayer: ZLMRTCClient is not available. Build might have failed.');
    }

    // 灵活的音频控制：优先级 webrtcConfig > 回退策略 > 用户设置 > 默认值
    let audioEnable;
    if (this.options.webrtcConfig && this.options.webrtcConfig.audioEnable !== undefined) {
      // webrtcConfig 中明确设置 - 最高优先级
      audioEnable = this.options.webrtcConfig.audioEnable;
    } else if (this.webrtcState.isRetryWithVideoOnly) {
      // 回退模式：强制禁用音频
      audioEnable = false;
    } else if (this.options.recvAudio !== undefined) {
      // 用户明确设置
      audioEnable = this.options.recvAudio;
    } else {
      // 默认启用音频（与 web 项目保持一致）
      audioEnable = true;
    }

    // WebRTC 配置 - 可以通过 options.webrtcConfig 来自定义
    const defaultWebRTCConfig = {
      element: this.element,
      zlmsdpUrl: this.options.url,
      debug: this.options.debug,
      recvOnly: true,
      audioEnable: audioEnable,
      videoEnable: this.options.recvVideo !== false,  // 默认启用视频
      // 添加 web 项目中兼容 1.0.1 版本的默认配置
      simulcast: false,     // 关键：禁用多路视频编码，避免额外的媒体流
      useCamera: false,
      usedatachannel: false
    };

    // 合并用户自定义的 WebRTC 配置
    const webrtcConfig = {
      ...defaultWebRTCConfig,
      ...(this.options.webrtcConfig || {})
    };

    // 强制确保音频完全禁用 - 防止 ZLMRTCClient 内部逻辑问题
    if (webrtcConfig.audioEnable === false) {
      webrtcConfig.audioEnable = false;
      // 确保不会有任何音频相关的 transceiver
      webrtcConfig.audioConstraints = false;
      
      // 添加特殊标记，用于后续的 SDP 处理
      webrtcConfig._forceVideoOnly = true;
    }

    if (this.options.debug) {
      let strategy = '';
      if (this.options.webrtcConfig && this.options.webrtcConfig.audioEnable !== undefined) {
        strategy = this.options.webrtcConfig.audioEnable ? 'webrtcConfig启用音频' : 'webrtcConfig禁用音频';
      } else if (this.webrtcState.isRetryWithVideoOnly) {
        strategy = '回退模式(禁用音频)';
      } else if (this.options.recvAudio === true) {
        strategy = '用户启用音频';
      } else if (this.options.recvAudio === false) {
        strategy = '用户禁用音频';
      } else {
        strategy = '默认启用音频(与web项目一致)';
      }
      console.log('WebRPlayer: Audio strategy -', strategy);
      console.log('WebRTC Config:', webrtcConfig);
    }
    
    this.player = new ZLMRTCClient.Endpoint(webrtcConfig);

    // 重要：ZLM 在 recvOnly=true 时会在构造器里直接开始 receive()
    // 为避免后续 play() 再次调用 receive() 导致重复添加 transceiver/多余 m-line，
    // 这里立即标记为连接中，并启动超时监控。
    this.webrtcState.isConnecting = true;
    if (!this.webrtcTimeoutId) {
      this.webrtcTimeoutId = setTimeout(() => {
        if (this.webrtcState.isConnecting && !this.webrtcState.hasStartedReceiving) {
          console.log('WebRTC: 连接超时，可能发生 SDP 协商错误');
          this._handleWebRTCError({
            type: 'connection_timeout',
            details: 'WebRTC connection timeout, possibly due to SDP negotiation failure'
          });
        }
      }, 10000);
    }

    // 添加特殊的错误监听器，快速检测 mid='1' 音频解复用错误
    this.player.on('error', (error) => {
      if (error && error.message && 
          (error.message.includes("Failed to set up audio demuxing for mid='1'") ||
           error.message.includes("audio demuxing"))) {
        console.warn('WebRTC: 检测到 mid=1 音频解复用错误，这通常是服务器配置问题');
        // 立即触发回退机制
        this._handleWebRTCError({
          type: 'sdp_audio_demux_error',
          details: 'Mid=1 audio demuxing failed - server configuration issue'
        });
        return;
      }
    });

    // Map events
    this.player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, (e) => {
      this.webrtcState.hasStartedReceiving = true;
      
      // 清除超时检测
      if (this.webrtcTimeoutId) {
        clearTimeout(this.webrtcTimeoutId);
        this.webrtcTimeoutId = null;
      }
      
      this._dispatchEvent('ready', { streams: e.streams });
      this._dispatchEvent('play');
    });

    this.player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {
      this._handleWebRTCError({
        type: 'exchange_failed',
        details: e
      });
    });

    this.player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, (state) => {
      if (this.options.debug) {
        console.log('WebRTC Connection state changed:', state);
      }
      
      if (state === 'connecting') {
        this.webrtcState.isConnecting = true;
        this.webrtcState.isConnected = false;
      } else if (state === 'connected') {
        this.webrtcState.isConnecting = false;
        this.webrtcState.isConnected = true;
      } else if (state === 'failed' || state === 'disconnected') {
        this.webrtcState.isConnecting = false;
        this.webrtcState.isConnected = false;
        this.webrtcState.hasStartedReceiving = false;
        
        // 如果连接失败且用户启用了音频，尝试回退策略
        if (state === 'failed' && !this.webrtcState.isRetryWithVideoOnly) {
          this._handleWebRTCError({
            type: 'connection_failed',
            details: 'WebRTC connection state changed to failed'
          });
          return; // 不继续分发事件，让回退策略处理
        }
      }
      
      this._dispatchEvent('connectionstatechange', { state });
    });

    // 监听 ICE 候选错误
    this.player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {
      if (this.options.debug) {
        console.log('WebRTC ICE Candidate Error:', e);
      }
      this._handleWebRTCError({
        type: 'ice_candidate_error',
        details: e
      });
    });
  }

  /**
   * Initialize an HLS player
   * @private
   */
  _initHLSPlayer() {
    // Check if Hls.js is available
    if (typeof Hls !== 'undefined' && Hls.isSupported()) {
      const hls = new Hls({
        debug: this.options.debug
      });
      hls.loadSource(this.options.url);
      hls.attachMedia(this.element);
      
      hls.on(Hls.Events.MANIFEST_PARSED, () => {
        this._dispatchEvent('ready');
      });

      hls.on(Hls.Events.ERROR, (event, data) => {
        this._dispatchEvent('error', { type: 'hls_error', details: data });
      });

      this.player = hls;
    } 
    else if (this.element.canPlayType('application/vnd.apple.mpegurl')) {
      // Native HLS support (Safari)
      this.element.src = this.options.url;
      this._setupHTMLVideoEvents();
      this.player = this.element;
    }
    else {
      throw new Error('WRPlayer: HLS is not supported in this browser');
    }
  }

  /**
   * Initialize a DASH player
   * @private
   */
  _initDASHPlayer() {
    // Check if dash.js is available
    if (typeof dashjs !== 'undefined') {
      const dashPlayer = dashjs.MediaPlayer().create();
      dashPlayer.initialize(this.element, this.options.url, this.options.autoplay);
      
      if (this.options.debug) {
        dashPlayer.updateSettings({ 'debug': { 'logLevel': dashjs.Debug.LOG_LEVEL_DEBUG } });
      }
      
      this.player = dashPlayer;
      this._setupHTMLVideoEvents();
    } else {
      throw new Error('WRPlayer: DASH is not supported, please include dash.js');
    }
  }

  /**
   * Initialize a regular HTML5 video player
   * @private
   */
  _initHTMLPlayer() {
    this.element.src = this.options.url;
    if (this.options.autoplay) {
      this.element.autoplay = true;
    }
    
    this._setupHTMLVideoEvents();
    this.player = this.element;
  }

  /**
   * Set up event listeners for HTML5 video elements
   * @private
   */
  _setupHTMLVideoEvents() {
    // Map standard HTML5 video events to our event system
    const events = ['play', 'pause', 'ended', 'timeupdate', 'seeking', 'seeked', 'waiting', 'loadedmetadata', 'loadeddata'];
    
    events.forEach(eventName => {
      this.element.addEventListener(eventName, () => {
        this._dispatchEvent(eventName);
      });
    });

    this.element.addEventListener('canplay', () => {
      this._dispatchEvent('ready');
    });

    this.element.addEventListener('error', () => {
      this._dispatchEvent('error', { 
        type: 'video_error', 
        details: this.element.error 
      });
    });
  }

  /**
   * Start playing the video
   */
  play() {
    const type = this.options.type.toLowerCase();
    
    if (type === 'webrtc') {
      if (this.player) {
        // 防止重复播放：如果已经在连接中或已经开始接收，不再重复调用
        if (this.webrtcState.isConnecting || this.webrtcState.hasStartedReceiving) {
          console.log('WebRTC: Already connecting or receiving, skipping duplicate play() call');
          return;
        }
        
        console.log('WebRTC: Starting receive...');
        this.webrtcState.isConnecting = true;
        
        try {
          this.player.receive();
          
          // 设置一个超时来检测是否连接成功
          this.webrtcTimeoutId = setTimeout(() => {
            if (this.webrtcState.isConnecting && !this.webrtcState.hasStartedReceiving) {
              console.log('WebRTC: 连接超时，可能发生 SDP 协商错误');
              this._handleWebRTCError({
                type: 'connection_timeout',
                details: 'WebRTC connection timeout, possibly due to SDP negotiation failure'
              });
            }
          }, 10000); // 10秒超时
          
        } catch (error) {
          console.error('WebRTC: receive() 调用失败:', error);
          this._handleWebRTCError({
            type: 'receive_failed',
            details: error
          });
        }
      }
    } else {
      const playPromise = this.element.play();
      if (playPromise !== undefined) {
        playPromise.catch(error => {
          console.error('WRPlayer: Play error', error);
          this._dispatchEvent('error', { type: 'play_failed', details: error });
        });
      }
    }
  }

  /**
   * Pause the video
   */
  pause() {
    const type = this.options.type.toLowerCase();
    
    if (type !== 'webrtc') {
      this.element.pause();
    }
    // WebRTC streams typically can't be paused
  }

  /**
   * Stop and close the player
   */
  stop() {
    // 检查 this.options.type 是否存在
    const type = this.options.type ? this.options.type.toLowerCase() : '';
    
    if (type === 'webrtc') {
      if (this.player) {
        this.player.close();
      }
      // 重置 WebRTC 状态
      this.webrtcState = {
        isConnecting: false,
        isConnected: false,
        hasStartedReceiving: false,
        isRetryWithVideoOnly: false,
        retryCount: 0
      };
    } else if (type === 'hls' && typeof Hls !== 'undefined' && this.player instanceof Hls) {
      this.player.destroy();
    } else if (type === 'dash' && typeof dashjs !== 'undefined') {
      this.player.destroy();
    }

    // Clean up the video element
    if (this.element) {
      this.element.src = '';
      this.element.srcObject = null;
      this.element.load();
    }
  }

  /**
   * 回退策略：使用仅视频模式重试连接
   * @private
   */
  _retryWithVideoOnly() {
    console.log('WebRTC: 开始回退策略，停止当前连接...');
    
    // 增加重试计数
    this.webrtcState.retryCount++;
    this.webrtcState.isRetryWithVideoOnly = true;
    
    // 停止当前播放器
    if (this.player) {
      this.player.close();
      this.player = null;
    }
    
    // 重置连接状态但保留重试标志
    this.webrtcState.isConnecting = false;
    this.webrtcState.isConnected = false;
    this.webrtcState.hasStartedReceiving = false;
    
    // 延迟重新初始化，确保资源完全释放
    setTimeout(() => {
      try {
        console.log('WebRTC: 重新初始化播放器（仅视频模式）...');
        this._initWebRTCPlayer();
        
        // 延迟开始播放
        setTimeout(() => {
          if (this.player && !this.webrtcState.isConnecting) {
            console.log('WebRTC: 开始接收（仅视频模式）...');
            this.webrtcState.isConnecting = true;
            this.player.receive();
          }
        }, 500);
      } catch (error) {
        console.error('WebRTC: 回退策略失败:', error);
        this._dispatchEvent('error', { 
          type: 'retry_failed', 
          details: { originalError: error, retryMode: 'video_only' }
        });
      }
    }, 1000);
  }

  /**
   * 处理 WebRTC 错误并尝试回退策略
   * @private
   */
  _handleWebRTCError(errorInfo) {
    console.log('WebRTC: 处理错误:', errorInfo);
    
    const errorString = JSON.stringify(errorInfo.details || errorInfo);
    const isSdpError = errorString.includes('setRemoteDescription') || 
                       errorString.includes('m-lines') || 
                       errorString.includes('demuxing') ||
                       errorInfo.type === 'connection_timeout';
    
    if (isSdpError && !this.webrtcState.isRetryWithVideoOnly && this.webrtcState.retryCount < 2) {
      console.log('WebRTC: 检测到 SDP 相关错误，尝试回退到仅视频模式');
      this._retryWithVideoOnly();
    } else {
      // 重置连接状态
      this.webrtcState.isConnecting = false;
      this._dispatchEvent('error', { 
        type: errorInfo.type || 'webrtc_error', 
        details: errorInfo.details 
      });
    }
  }

  /**
   * Register an event handler
   * @param {string} event - Event name
   * @param {Function} callback - Event handler function
   */
  on(event, callback) {
    if (!this.eventHandlers[event]) {
      this.eventHandlers[event] = [];
    }
    this.eventHandlers[event].push(callback);
    return this;
  }

  /**
   * Remove an event handler
   * @param {string} event - Event name
   * @param {Function} callback - Event handler function to remove
   */
  off(event, callback) {
    if (!this.eventHandlers[event]) return this;
    
    if (callback) {
      const index = this.eventHandlers[event].indexOf(callback);
      if (index !== -1) {
        this.eventHandlers[event].splice(index, 1);
      }
    } else {
      this.eventHandlers[event] = [];
    }
    
    return this;
  }

  /**
   * Dispatch an event to registered handlers
   * @private
   * @param {string} event - Event name
   * @param {Object} data - Event data
   */
  _dispatchEvent(event, data = {}) {
    if (this.options.debug) {
      console.log(`WRPlayer Event: ${event}`, data);
    }
    
    if (this.eventHandlers[event]) {
      this.eventHandlers[event].forEach(handler => {
        handler(data);
      });
    }
  }

  /**
   * Get the current player instance
   * @returns {Object} The underlying player instance
   */
  getPlayer() {
    return this.player;
  }

  /**
   * Check if player supports a given media type
   * @param {string} type - Media type to check
   * @returns {boolean} Whether the type is supported
   */
  static isSupported(type) {
    // Check if we're in a browser environment
    if (typeof window === 'undefined') {
      return false;
    }

    switch (type.toLowerCase()) {
      case 'webrtc':
        // Since ZLMRTCClient is now a direct import, we assume it's supported if this code runs.
        return true; 
      case 'hls':
        return (typeof Hls !== 'undefined' && Hls.isSupported()) || 
               document.createElement('video').canPlayType('application/vnd.apple.mpegurl');
      case 'dash':
        return typeof dashjs !== 'undefined';
      case 'mp4':
        return document.createElement('video').canPlayType('video/mp4') !== '';
      case 'webm':
        return document.createElement('video').canPlayType('video/webm') !== '';
      default:
        return false;
    }
  }
}

// Export to make available in different module systems
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
  module.exports = WRPlayer;
} else if (typeof window !== 'undefined') {
  window.WRPlayer = WRPlayer;
}

// Add ESM export for modern bundlers
export default WRPlayer; 